/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package shaman.storage.impl.stream.gather;

import java.io.IOException;
import java.io.InputStream;

/**
 *
 * @author dmitriy
 */
public class GatherInputStream extends InputStream {

    private final PartStreamFactory fact;
    private InputStream curStream;
    private long curPos;

    public GatherInputStream(PartStreamFactory fact) {
        this.fact = fact;
        curStream=null;
        curPos=0;
    }

    private synchronized boolean checkOpenStream() throws IOException {
        if (curStream!=null)
            return true;
        curStream=fact.getInputStream(curPos);
        return (curStream!=null);
    }

    private synchronized void closeStream() throws IOException {
        if (curStream!=null)
            curStream.close();
        curStream=null;
    }

    @Override
    public synchronized int available() throws IOException {
        if (!checkOpenStream())
            return 0;
        return curStream.available();
    }

    @Override
    public void close() throws IOException {
        closeStream();
    }

    @Override
    public synchronized void mark(int readlimit) {
    }

    @Override
    public boolean markSupported() {
        return false;
    }

    @Override
    public synchronized int read() throws IOException {
        int val=-1;
        while (checkOpenStream())
        {
            val=curStream.read();
            if (val<0)
                closeStream();
            else
                break;
        }
        curPos++;
        return val;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int rdlen=0;
        int closeCount=0;
        while (checkOpenStream())
        {
            int steplen;
            steplen=curStream.read(b, off+rdlen, len-rdlen);
            if (steplen<0)
            {
                closeStream();
                closeCount++;
            }
            else {
                closeCount=0;
                rdlen+=steplen;
                curPos+=steplen;
            }
            if (rdlen>=len || closeCount>1) break;
        }
        if (rdlen==0) rdlen=-1;
        return rdlen;
    }

    @Override
    public synchronized void reset() throws IOException {
        closeStream();
        curPos=0;
    }

}
